
#include <BPainter>
#include <BStyle>
#include <BMouseEvent>
#include <BLine2>

#include <BGraphicWidget>
#include <BStripeItem>
#include "member_BStripeItem.h"

using namespace BWE;

#define member					(*(member_BStripeItem*)_ptr)
#define member_allocate()		_ptr = new member_BStripeItem(this)
#define member_release()		delete (member_BStripeItem*)_ptr

BStripeItem::BStripeItem(BGraphicItem* parent) : BGraphicItem(parent)
{
	member_allocate();
}
BStripeItem::~BStripeItem()
{
	member_release();
}

void BStripeItem::setLineWidth(float lineWidth)
{
	if (member.lineWidth != lineWidth)
	{
		member.lineWidth = lineWidth;
		this->emit(Signal_Changed);
		this->fresh();
	}
}
float BStripeItem::lineWidth() const
{
	return member.lineWidth;
}

void BStripeItem::setLineColor(const BColor& lineColor)
{
	if (member.lineColor != lineColor)
	{
		member.lineColor = lineColor;
		this->emit(Signal_Changed);
		this->fresh();
	}
}
const BColor& BStripeItem::lineColor() const
{
	return member.lineColor;
}

bool BStripeItem::addPoint(const BPointf& point)
{
	if (member.points.append(point))
	{
		member.dirty = true;
		this->emit(Signal_Dirty);
		this->fresh();
	}
	return true;
}
bool BStripeItem::setPoint(int index, const BPointf& point)
{
	if (member.points.check(index))
	{
		member.points[index] = point;
		member.dirty = true;
		this->emit(Signal_Dirty);
		this->fresh();
		return true;
	}
	return false;
}
bool BStripeItem::insertPoint(int pos, const BPointf& point)
{
	if (member.points.insert(pos, point))
	{
		member.dirty = true;
		this->emit(Signal_Dirty);
		this->fresh();
		return true;
	}
	return false;
}
bool BStripeItem::removePoint(int pos)
{
	if (member.points.remove(pos))
	{
		member.dirty = true;
		this->emit(Signal_Dirty);
		this->fresh();
		return true;
	}
	return false;
}

int BStripeItem::pointCount() const
{
	return member.points.size();
}
const BPointf& BStripeItem::point(int index) const
{
	return member.points.at(index);
}

const BRectf& BStripeItem::pointRect() const
{
	return member.pointArea;
}

BSizef BStripeItem::sizeHint() const
{
	if (member.dirty)
	{
		member.freshSize();
		member.dirty = false;
	}
	return this->preferSize(member.pointArea.size());
}

bool BStripeItem::catchPoint(const BPointf& point) const
{
	for (int i = 1; i < member.points.size(); i++)
	{
		const BPointf& p0 = member.points[i - 1];
		const BPointf& p1 = member.points[i];
		BLine2f line(p0, p1);
		BPointf clsp = line.closest(point, false);
		float dist = (clsp - point).length();
		if (dist < 5)
			return true;
	}
	return false;
}

void BStripeItem::paint(BPainter& painter)
{
	if (member.points.size() > 1)
	{
		State state = painter.state();
		if (this->hovered())
			state |= State_Hovered;
		else if (this->selected())
			state |= State_Selected;

		painter.setPolySmooth(true);
		if (member.lineColor.a())
			painter.setColor(member.lineColor);
		else
			painter.setColor(Color_Line, state);
		painter.setLineWidth(member.lineWidth);
		painter.drawLineStrip(member.points);
		painter.setPolySmooth(false);
	}
}

void BStripeItem::styleEvent(const BEvent& event)
{
	BGraphicItem::styleEvent(event);
	const BStyle* style = event.value();
	const BValue& lineWidthValue = style->value(Value_Line_Width);
	if (lineWidthValue.valid())
		member.lineWidth = lineWidthValue;
}
void BStripeItem::freshEvent(const BEvent& event)
{
	BGraphicItem::freshEvent(event);
	if (member.dirty)
	{
		member.freshSize();
		member.dirty = false;
	}
}

